package com.core.toolkit;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.core.mapper.ReservationMapper;
import com.core.mapper.UserBlacklistMapper;
import com.core.pojo.Result.Result;
import com.core.pojo.SeatReservation.Enum.ReservationStatusEnum;
import com.core.pojo.SeatReservation.entity.Reservation;
import com.core.pojo.User.dto.UserBlacklistDTO;
import com.core.pojo.User.entity.UserBlacklist;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.List;

import static com.core.constant.RedisConstants.USER_BLACKLIST_KEY;

/**
 * 每日用户管理
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class DailyUserManage extends ServiceImpl<UserBlacklistMapper, UserBlacklist> {

    private final ReservationMapper reservationMapper;
    private final UserBlacklistMapper userBlacklistMapper;
    private final StringRedisTemplate stringRedisTemplate;

    /**
     * 创建黑名单列表
     * 遍历整个reservation表，查询expired超过三次的人
     */
    @Transactional(rollbackFor = Exception.class)
    public void buildUserBlacklist(){
        // 获取所有预约过用户的恶意占座次数
        List<UserBlacklistDTO> UserBlacklistDTOList=reservationMapper.selectUserIdsWithExpiredCount();
        List<UserBlacklist> UserBlacklistList = UserBlacklistDTOList.stream()
                .map(dto -> {
                    UserBlacklist userBlacklist = new UserBlacklist();
                    userBlacklist.setId(dto.getUserId());
                    userBlacklist.setExpiredCount(dto.getExpiredCount());
                    // 判断过期次数是否超过3，超过则加入黑名单
                    userBlacklist.setBlacklisted(dto.getExpiredCount() >= 3);
                    return userBlacklist;
                }).toList();
        //写入数据库
        this.remove(new QueryWrapper<>()); // 清空表
        this.saveBatch(UserBlacklistList);
        //批量写入redis
        String[] blacklistedIds = UserBlacklistList.stream()
                .filter(UserBlacklist::isBlacklisted) // 过滤，仅写入黑名单的用户id
                .map(u -> u.getId().toString())
                .distinct() // 可选：去重，防御性处理
                .toArray(String[]::new);
        // 因为是全量重建黑名单，先清空旧集合再写入
        stringRedisTemplate.delete(USER_BLACKLIST_KEY);
        if (blacklistedIds.length > 0) {
            stringRedisTemplate.opsForSet().add(USER_BLACKLIST_KEY, blacklistedIds);
        }
    }

    /**
     * 每天凌晨00:05执行，维护黑名单数据
     * 1. 把上一天预约为签到的预约状态改为 EXPIRED
     * 2. 将这些用户的 EXPIRED 次数 +1 （没有就创建条目）
     * 3. 如果次数大于二直接加入黑名单
     */
    // 这个版本效率非常低，是先试着写这样
    @Scheduled(cron = "0 5 0 * * ?")
    @Transactional
    public Result LastDayReservationStatusMaintenanceV1(){
        QueryWrapper<Reservation> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("date", LocalDate.now().minusDays(1));
        List<Reservation> LastDayReservationList=reservationMapper.selectList(queryWrapper);
        for(Reservation reservation:LastDayReservationList){
            if(reservation.getStatus()== ReservationStatusEnum.ACTIVE_NOT_CHECKED){
                reservation.setStatus(ReservationStatusEnum.EXPIRED);
            }
            QueryWrapper<UserBlacklist> queryWrapper2 = new QueryWrapper<>();
            queryWrapper2.eq("id", reservation.getUserId());
            UserBlacklist userBlackList= userBlacklistMapper.selectOne(queryWrapper2);
            // 假如存在该用户的黑名单信息的话
            if(userBlackList!=null){
                userBlackList.setExpiredCount(userBlackList.getExpiredCount()+1);
                // 恶意占座次数超过二的话
                if(userBlackList.getExpiredCount()>=3){
                    userBlackList.setBlacklisted(true);
                    stringRedisTemplate.opsForSet().add(USER_BLACKLIST_KEY,userBlackList.getId().toString());
                }
                userBlacklistMapper.updateById(userBlackList);
            }else{
                // 假如不存在该用户的黑名单信息的话
                userBlackList=new UserBlacklist();
                userBlackList.setId(reservation.getUserId());
                userBlackList.setExpiredCount(1);
                userBlackList.setBlacklisted(false);
                userBlacklistMapper.insert(userBlackList);
            }
        }
        return Result.success("黑名单维护完成");
    }

    @Scheduled(cron = "0 5 0 * * ?")
    @Transactional(rollbackFor = Exception.class)
    public Result lastDayReservationStatusMaintenance() {
        LocalDate yesterday = LocalDate.now().minusDays(1);

        // 1. 一次性更新昨天未签到的预约状态为 EXPIRED
        UpdateWrapper<Reservation> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("date", yesterday)
                .eq("status", ReservationStatusEnum.ACTIVE_NOT_CHECKED)
                .set("status", ReservationStatusEnum.EXPIRED);
        reservationMapper.update(null, updateWrapper);

        // 2. 按用户统计昨天新增的 EXPIRED 次数
        List<UserBlacklistDTO> expiredCountList = reservationMapper.selectExpiredCountByUser(yesterday);
        if (expiredCountList.isEmpty()) {
            return Result.success("无需要处理的数据");
        }

        // 3. 批量 upsert 黑名单表
        //   用 INSERT ... ON DUPLICATE KEY UPDATE（效率最高）
        for (UserBlacklistDTO dto : expiredCountList) {
            userBlacklistMapper.insertOrUpdateExpiredCount(dto);
        }

        // 4. 查询哪些用户已经被拉黑，一次性写入 Redis
        List<String> blacklistedUserIds = userBlacklistMapper.selectList(
                new QueryWrapper<UserBlacklist>().eq("blacklisted", true)
        ).stream().map(u -> u.getId().toString()).toList();

        if (!blacklistedUserIds.isEmpty()) {
            stringRedisTemplate.opsForSet().add(USER_BLACKLIST_KEY, blacklistedUserIds.toArray(new String[0]));
        }

        return Result.success("黑名单维护完成");
    }

}
